﻿//
// *************************************************************************************
// WP-Framework
//
// Developed by 
// Lukas Kretschmar (lkretschmar.dev@bluewin.ch)
//
// Switzerland, Copyright (c) 2013 lkretschmar
// This content is released under the MIT License (http://opensource.org/licenses/MIT).
//     
// *************************************************************************************
//
//
			

using System;
using System.Linq.Expressions;
using System.Linq;
using Expression = System.Linq.Expressions.Expression;
using KretschIT.WP_Fx.Core.Validation;
using System.Collections.Generic;
using KretschIT.WP_Fx.Core.Extensions;

namespace KretschIT.WP_Fx.EasyMoq.Matchers
{
    internal class OnlyMatcher : ConditionalMatcher
    {
        public OnlyMatcher(MethodCallExpression expression)
            : base(expression)
        {
            this.Lambda = this.GetConditionFrom(expression);
            It.IsValid(() => expression, e => this.Lambda != null);
        }

        private LambdaExpression Lambda { get; set; }

        private LambdaExpression GetConditionFrom(MethodCallExpression expression)
        {
            var lambda = this.GetLambdaFrom<UnaryExpression>(expression, e => e.Operand);
            if (lambda == null)
            {
                lambda = this.GetLambdaFrom<MemberExpression>(expression, e => e.GetValue());
            }
            return lambda;           
        }

        private LambdaExpression GetLambdaFrom<TExpression>(MethodCallExpression expression, Func<TExpression, object> get) where TExpression : Expression
        {
            var expr = this.TryGet<TExpression>(expression.Arguments);
            if (expr == null)
            {
                return null;
            }
            return get(expr) as LambdaExpression;
        }

        private TExpression TryGet<TExpression>(IEnumerable<Expression> arguments) where TExpression : Expression
        {
            return arguments.OfType<TExpression>().SingleOrDefault();
        }
        
        protected override Func<object, bool> Condition
        {
            get { return v => this.ExecuteConditionOfExpression(v); }
        }        

        private bool ExecuteConditionOfExpression(object value)
        {
            return (bool)this.Lambda.Compile().DynamicInvoke(value);
        }
    }
}
